﻿using MySSO.Core;
using MySSO.Core.Entity;
using MySSO.Core.Service;
using MySSOMVC.Models;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MySSOMVC.Controllers
{
    public class AuthorizeController : Controller
    {
        private readonly MemoryCacheManager memoryCacheManager;
        private readonly AdminUserService _adminUserService;
        private readonly WebHelper _webHelper;
        private readonly AdminVisitService _adminVisitService;
        private readonly string tokensecret = System.Configuration.ConfigurationManager.AppSettings["tokensecret"];
        public AuthorizeController()
        {
            memoryCacheManager = new MemoryCacheManager();
            _adminUserService = new AdminUserService();
            _webHelper = new WebHelper();
            _adminVisitService = new AdminVisitService();
        }


        /// <summary>
        /// 验证页面
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public ActionResult Index(AuthorizeRequest request)
        {
            HttpCookie AuthCookie = Request.Cookies[AppConstants.Cookie.AUTH_COOKIE];

            if (AuthCookie != null)
            {
                //Authentication Cookie is available in Request. So, check whether it is expired or not.
                //and redirect to appropriate location based upon the cookie status
                return CheckCookie(AuthCookie, request.ReturnUrl,request.State);
            }
            else
            {
                return RedirectToAction("Login", "Authorize", new { ReturnUrl = request.ReturnUrl,State=request.State });
            }

        }

        /// <summary>
        /// 登录页面
        /// </summary>
        /// <param name="ReturnUrl"></param>
        /// <returns></returns>
        [HttpGet]
        public ActionResult Login(string ReturnUrl,string State)
        {
            ViewBag.ReturnUrl = ReturnUrl;
            ViewBag.State = State;
            _adminVisitService.AccessRecord();
            return View();
        }

        /// <summary>
        /// 登录方法
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginRequest request)
        {
           
            ViewBag.ReturnUrl = request.ReturnUrl;
            ViewBag.State = request.State;
            if (string.IsNullOrWhiteSpace(request.Password) || string.IsNullOrWhiteSpace(request.UserName))
            {
                ViewBag.Error = "用户名和密码不能为空";
                return View();
            }
            //CurrentUser = AuthUtil.Instance.Authenticate(UserName, Password);
            //AuthUser authUser = null;
            //if (request.UserName=="lindy" && request.Password=="lindy")
            //{
            //    authUser = new AuthUser();
            //    authUser.UserName = "lindy";
            //    authUser.Password = "lindy";
            //    authUser.Id = "667883";
            //}
            long RID = _adminVisitService.GetVistRecordId();
            int r = 0;
            string clientinfo = _webHelper.GetClientInfo();
            string ipString = _webHelper.GetCurrentIpAddress();

            AdminUserEntity user = _adminUserService.Login(request.UserName, request.Password, ipString, RID, clientinfo, out r);
            if (r == 1)
            {
                //之前登录的账号的token登出
                HttpCookie Cookie = Request.Cookies[AppConstants.Cookie.AUTH_COOKIE];
                if (Cookie!=null)
                {
                    memoryCacheManager.Remove(Cookie.Value);
                }
               

                string token = Guid.NewGuid().ToString();
                this.SetAuthCookie(token);
                //UserSSoModel userSSoModel = new UserSSoModel();
                //userSSoModel.username = user.Name;
                //userSSoModel.uid = user.AUID.ToString();
                //memoryCacheManager.Set(token, userSSoModel, 30);
                string idtoken=IdtokenHelper.GenerateIdtoken(user, token, AppConstants.TokenExpireTime, tokensecret);
                memoryCacheManager.Set(token, idtoken, 30);
                string returnUrl = request.ReturnUrl;
                if (string.IsNullOrEmpty(returnUrl))
                {
                    return RedirectToAction("Index", "Home");
                }
                else
                {
                    returnUrl = Utility.GetAppendedQueryString(returnUrl, AppConstants.UrlParams.TOKEN, idtoken);
                    returnUrl = Utility.GetAppendedQueryString(returnUrl, AppConstants.UrlParams.State, request.State);
                    return Redirect(returnUrl);
                }

            }
            else
            {
                string errormsg = "";

                switch (r)
                {
                    case 0:
                        errormsg = "输入的Email或密码不正确！";
                        break;
                    case -1:
                        errormsg = "输入的Email或密码不正确！";
                        break;
                    case -2:
                        errormsg = "账户输入错误超过5次，被锁定24小时";
                        break;
                    case -3:
                        errormsg = "该账户已被禁用";
                        break;
                    case -4:
                        errormsg = "密码过于简单，又没有在24小时内修改，账户已被锁定。";
                        break;
                    default:
                        errormsg = "未知错误";
                        break;
                        //

                }

                ViewBag.Error = errormsg;
                return View();
            }
           
        }

        

        public ActionResult Logout(string token,string returnUrl)
        {
            //if (CurrentUser == null)
            //{
            //    RedirectToLoginPage();
            //    return;
            //}
            //string currentURL = Request.Url.OriginalString;
            //currentURL = UriUtil.RemoveParameter(currentURL, AppConstants.UrlParams.REQUEST_ID);
            //currentURL = UriUtil.RemoveParameter(currentURL, AppConstants.UrlParams.TOKEN);

            //string ssoSiteUrl = string.Format(SSOSiteUrlConfig, HttpUtility.UrlEncode(currentURL));
            //string LogoutUrl = string.Format("{0}&{1}={2}&{3}={4}", ssoSiteUrl, AppConstants.UrlParams.ACTION, AppConstants.ParamValues.LOGOUT, AppConstants.UrlParams.TOKEN, SessionAPI.CurrentUser.Token);
            //CurrentUser = null;
            //Response.Redirect(LogoutUrl);
            if(string.IsNullOrWhiteSpace(returnUrl))
            {
                returnUrl = Url.Action("Index", "Home");
            }
           return  LogoutUser(token,returnUrl);
            
        }


        /// <summary>
        /// If the Cookie is available, check the expiry of the authentication Cookie.
        /// Also, add Token and redirect
        /// </summary>
        /// <param name="AuthCookie"></param>
        /// <param name="ReturnUrl"></param>
        private ActionResult CheckCookie(HttpCookie AuthCookie, string ReturnUrl,string State)
        {
            string Token = Utility.GetCookieValue(AuthCookie);
            string idtoken= memoryCacheManager.Get<string>(Token);

            DateTime expirytime = Utility.GetExpirationDate(AuthCookie);
            //Check if the Cookie is expired and Token is available
            try
            {
                IDictionary<string, object> payload = JWTHelper.Decode(idtoken, tokensecret);
                UserSSoModel userSSoModel = new UserSSoModel();
                userSSoModel.token = payload["token"].ToString();
                userSSoModel.uid = payload["uid"].ToString();
                userSSoModel.username = payload["name"].ToString();

                //刷新token,token过期时间为5分钟
                idtoken=IdtokenHelper.RefreshIdtoken(payload, AppConstants.TokenExpireTime, tokensecret);
                memoryCacheManager.Set(Token, idtoken, 30);
            }
            catch
            {
                //Cookie is expired. So, remove the Cookie from the Response
                RemoveCookie(AuthCookie);
                //Mark the user's presence as Null in the application scope
                memoryCacheManager.Remove(Token);
                //Redirect to the site URL
                return RedirectToAction("Login", "Authorize", new { ReturnUrl = ReturnUrl, State = State });
                //return RedirectAction(ReturnUrl);
            }
            if (CookieExpired(expirytime))
            {
                //Cookie is expired. So, remove the Cookie from the Response
                RemoveCookie(AuthCookie);
                //Mark the user's presence as Null in the application scope
                memoryCacheManager.Remove(Token);
                //Redirect to the site URL
                return RedirectToAction("Login", "Authorize", new { ReturnUrl = ReturnUrl , State = State });
                //return RedirectAction(ReturnUrl);

            }
            else
            {
                //Check if Sliding expiration is set to true in web.config
                if (Config.SLIDING_EXPIRATION)
                {
                    //Sliding expiration is set to true. So, increase the expiry time for the Cookie

                    AuthCookie = IncreaseCookieExpiryTime(AuthCookie);
                }
            }
            if (string.IsNullOrEmpty(ReturnUrl))
            {
                return RedirectToAction("Index","Home");
            }
            else
            {
                if (!string.IsNullOrEmpty(Token) && !ReturnUrl.Contains(Token))
                {
                    //If Token is present in the QueryString, append it in the return URl and redirect
                    ReturnUrl = Utility.GetAppendedQueryString(ReturnUrl, AppConstants.UrlParams.TOKEN, idtoken);
                    ReturnUrl= Utility.GetAppendedQueryString(ReturnUrl, AppConstants.UrlParams.State, State);
                    return RedirectAction(ReturnUrl);
                }
                else
                {
                    //Cookie is expired or Token is not available. So, redirect user to the ReturnUrl.
                    return RedirectAction(ReturnUrl);
                }
            }
        }
        /// <summary>
        /// Mark user as being logged out of the site
        /// </summary>
        private ActionResult MarkUserLoggedOut(string returnUrl)
        {
            //Retrieve the Token from the ReturnUrl (If present)
            Uri uri = new Uri(returnUrl);
            NameValueCollection collection = HttpUtility.ParseQueryString(uri.Query);
            if (collection.Count > 0)
            {
                string Token = collection[AppConstants.UrlParams.TOKEN];
                //Mark the user's presence as Null in the corresponding user stored in Application scope
                if (!string.IsNullOrEmpty(Token))
                {
                    //Application[Token] = null;
                }
            }

            //Redirect user to the originally requested site URL
            return RedirectAction(returnUrl);
        }

        /// <summary>
        /// Set authentication cookie in Response
        /// </summary>
        private void SetAuthCookie(string token)
        {
            HttpCookie AuthCookie = new HttpCookie(AppConstants.Cookie.AUTH_COOKIE);

            //Set the Cookie's value with Expiry time and Token
            int CookieTimeoutInMinutes = Config.AUTH_COOKIE_TIMEOUT_IN_MINUTES;

            AuthCookie.Value = Utility.BuildCookueValue(token, CookieTimeoutInMinutes);

            Response.Cookies.Add(AuthCookie);

            //Redirect to the original site request
            //string url=Utility.GetAppendedQueryString(returnUrl, AppConstants.UrlParams.TOKEN, token);
            //return RedirectAction(url);
        }

        /// <summary>
        /// Logs out current user;
        /// </summary>
        private ActionResult LogoutUser(string token,string returnUrl)
        {
            //This is a logout request. So, remove the authentication Cookie from the response
            if (token != null)
            {
                HttpCookie Cookie = Request.Cookies[AppConstants.Cookie.AUTH_COOKIE];

                if (Cookie.Value == token)
                {
                    RemoveCookie(Cookie);
                }
                memoryCacheManager.Remove(token);

            }
            //Also, mark the user at the application scope as null
            //Application[Token] = null;

            //Redirect user to the desired location
            //ReturnUrl = GetAppendedQueryString(ReturnUrl, AppConstants.UrlParams.ACTION, AppConstants.ParamValues.LOGOUT);
            //string url = Url.Action("Login", "Authorize", new { ReturnUrl = returnUrl });
            return Redirect(returnUrl);
            //return RedirectAction(url);
        }


       


        /// <summary>
        /// Increases Cookie expiry time
        /// </summary>
        /// <param name="AuthCookie"></param>
        /// <returns></returns>
        private HttpCookie IncreaseCookieExpiryTime(HttpCookie AuthCookie)
        {
            string Token = Utility.GetCookieValue(AuthCookie);
            DateTime Expirytime = Utility.GetExpirationDate(AuthCookie);
            DateTime IncreasedExpirytime = Expirytime.AddMinutes(Config.AUTH_COOKIE_TIMEOUT_IN_MINUTES);

            Response.Cookies.Remove(AuthCookie.Name);

            HttpCookie NewCookie = new HttpCookie(AuthCookie.Name);
            NewCookie.Value = Utility.BuildCookueValue(Token, Config.AUTH_COOKIE_TIMEOUT_IN_MINUTES);

            Response.Cookies.Add(NewCookie);

            return NewCookie;
        }

        /// <summary>
        /// Removes Cookie from the response
        /// </summary>
        /// <param name="Cookie"></param>
        private void RemoveCookie(HttpCookie Cookie)
        {
            Response.Cookies.Remove(Cookie.Name);

            HttpCookie myCookie = new HttpCookie(Cookie.Name);
            myCookie.Expires = DateTime.Now.AddDays(-1d);
            Response.Cookies.Add(myCookie);
        }

        /// <summary>
        /// Determines whether the Cookie is expired or not
        /// </summary>
        /// <param name="expirytime"></param>
        /// <returns></returns>
        private bool CookieExpired(DateTime expirytime)
        {
            return expirytime.CompareTo(DateTime.Now) < 0;
        }

        /// <summary>
        /// Append a request ID to the URl and redirect
        /// </summary>
        /// <param name="Url"></param>
        private ActionResult RedirectAction(string Url)
        {
            //Generate a new RequestId and append to the Response URL. This is requred so that, the client site can always
            //determine whether the RequestId is originated from the SSO site or not
            //string RequestId = Utility.GetGuidHash();
            //string redirectUrl = Utility.GetAppendedQueryString(Url, AppConstants.UrlParams.REQUEST_ID, RequestId);

            //Save the RequestId in the Application 
            //Application[RequestId] = RequestId;
            return Redirect(Url);
          
        }

    }
}